package org.duoduo.common.redis.jedis3_1_0;

import com.duoduo.common.api.constants.Constant;
import com.duoduo.common.api.help.FutureTaskInnerUtil;
import com.duoduo.common.api.help.PropertiesInnerUtil;
import com.duoduo.common.api.tuple.Tuple;
import com.duoduo.common.api.tuple.TwoTuple;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import java.util.*;
import java.util.concurrent.Callable;

/**初始化redis客户端
 * @author duoduo
 *
 */
public class JedisCacheInit {
	
	private final static Map<String, TwoTuple<String, RedisPool>> redisPools = new HashMap<>();
	
	private JedisCacheInit(){
		
	}

	/**
	 * 初始化cluster/哨兵集群
	 */
	public static void initCluster(){
		FutureTaskInnerUtil.get("initRedis", new RedisExecutorCall());
	}
	
	private static class RedisExecutorCall implements Callable<RedisExecutor<Object>> {
		
		private static String names = PropertiesInnerUtil.getString(Constant.REDIS_PROP_LOCATION, Constant.REDIS_PROP_NAMES); // 是否配置了多集群
		
        @Override
        public RedisExecutor<Object> call() throws Exception {
        	if(StringUtils.isEmpty(names)) {
        		createExecutor(Constant.REDIS_PROP_DEFAULT_PRE_NAME, Constant.EMPTY_STRING);
        	}else {
        		String[] arr = StringUtils.split(names, Constant.COMMA);
        		for (int i=0; i<arr.length; i++) {
        			String name = arr[i];
        			createExecutor(name, name + Constant.DOT);
        			if(i == 0 && !name.equals(Constant.REDIS_PROP_DEFAULT_PRE_NAME)) {
        				// 针对第一个配置默认生成一个default key
        				createExecutor(Constant.REDIS_PROP_DEFAULT_PRE_NAME, name + Constant.DOT);
        			}
				}
        	}
        	return null;
        }

		private RedisExecutor<Object> createExecutor(String key, String prefix) {
			String redisClusterType = PropertiesInnerUtil.getString(Constant.REDIS_PROP_LOCATION, prefix + Constant.REDIS_PROP_CLUSTER_TYPE, Constant.REDIS_PROP_CLUSTER_TYPE_DEFAULT);//默认集群方式
			String servers = PropertiesInnerUtil.getString(Constant.REDIS_PROP_LOCATION, prefix + Constant.REDIS_PROP_SERVER, PropertiesInnerUtil.getString(Constant.REDIS_PROP_LOCATION, prefix + Constant.REDIS_PROP_SERVER_COMPATIBILITY));
			String password = PropertiesInnerUtil.getString(Constant.REDIS_PROP_LOCATION, prefix + Constant.REDIS_PROP_PASSWORD);
			Integer databases = PropertiesInnerUtil.getInteger(Constant.REDIS_PROP_LOCATION, prefix + Constant.REDIS_PROP_DATABASE, Constant.REDIS_PROP_DATABASE_DEFAULT);//使用哪个数据库
			String masterName = PropertiesInnerUtil.getString(Constant.REDIS_PROP_LOCATION, prefix + Constant.REDIS_PROP_MASTERNAME, Constant.REDIS_PROP_MASTERNAME_DEFAULT);//哨兵模式下的主机名
			int maxAttempts = PropertiesInnerUtil.getInteger(Constant.REDIS_PROP_LOCATION, prefix + Constant.REDIS_PROP_MAXATTEMPTS, Constant.REDIS_PROP_MAXATTEMPTS_DEFAULT);
			int maxTotal = PropertiesInnerUtil.getInteger(Constant.REDIS_PROP_LOCATION, prefix + Constant.REDIS_PROP_POOL_MAXTOTAL, Constant.REDIS_PROP_POOL_MAXTOTAL_DEFAULT);
			int maxIdle = PropertiesInnerUtil.getInteger(Constant.REDIS_PROP_LOCATION, prefix + Constant.REDIS_PROP_POOL_MAXIDLE, Constant.REDIS_PROP_POOL_MAXIDLE_DEFAULT);
			int minIdle = PropertiesInnerUtil.getInteger(Constant.REDIS_PROP_LOCATION, prefix + Constant.REDIS_PROP_POOL_MINIDLE, Constant.REDIS_PROP_POOL_MINIDLE_DEFAULT);
			int timeout = PropertiesInnerUtil.getInteger(Constant.REDIS_PROP_LOCATION, prefix + Constant.REDIS_PROP_CONN_TIMEOUT, Constant.REDIS_PROP_CONN_TIMEOUT_DEFAULT);
			int soTimeout = PropertiesInnerUtil.getInteger(Constant.REDIS_PROP_LOCATION, prefix + Constant.REDIS_PROP_SOTIMEOUT, Constant.REDIS_PROP_SOTIMEOUT_DEFAULT);
			int maxWaitMillis = PropertiesInnerUtil.getInteger(Constant.REDIS_PROP_LOCATION, prefix + Constant.REDIS_PROP_POOL_MAXWAIT_MILLIS, Constant.REDIS_PROP_POOL_MAXWAIT_MILLIS_DEFAULT);
			String appName = PropertiesInnerUtil.getString(Constant.REDIS_PROP_LOCATION, prefix + Constant.REDIS_PROP_APPNAME);
			
			Set<String> clusters = new HashSet<String>();
			if (servers != null){
				clusters.addAll(Arrays.asList(StringUtils.split(servers, "|")));
			}
			GenericObjectPoolConfig<?> poolConfig = new GenericObjectPoolConfig<>();
			poolConfig.setMaxTotal(maxTotal);
			poolConfig.setMaxIdle(maxIdle);
			poolConfig.setMinIdle(minIdle);
			poolConfig.setMaxWaitMillis(maxWaitMillis);
			poolConfig.setTestOnBorrow(true);
			poolConfig.setTestOnReturn(true);
			poolConfig.setTestWhileIdle(true);
			
			TwoTuple<String, RedisPool> redisPool = poolInit(redisClusterType, clusters, poolConfig, databases, masterName, timeout, soTimeout, maxAttempts, password, appName);
    		redisPools.put(key, redisPool);

    		return null;
		}
		
		private static TwoTuple<String, RedisPool> poolInit(String redisClusterType, Set<String> clusters, final GenericObjectPoolConfig poolConfig, int databases, String masterName, int timeout, int soTimeout, int maxAttempts, final String password, String _appName) {
        	RedisPool redisPool = new RedisPool(redisClusterType, clusters, poolConfig, databases, masterName, timeout, soTimeout, maxAttempts, password);
        	return Tuple.tuple(_appName, redisPool);
        }

    }
	
	public static TwoTuple<String, RedisPool> getPoolAndAppName(String key){
		return redisPools.get(key);
	}

}